// RUN: mlir-pdll %s -I %S -I %S/../../../../include -split-input-file -x mlir | FileCheck %s

//===----------------------------------------------------------------------===//
// AttributeExpr
//===----------------------------------------------------------------------===//

// CHECK: pdl.pattern @AttrExpr
// CHECK: %[[ATTR:.*]] = attribute = 10
// CHECK: operation({{.*}}) {"attr" = %[[ATTR]]}
Pattern AttrExpr => erase op<> { attr = attr<"10"> };

// -----

//===----------------------------------------------------------------------===//
// CallExpr
//===----------------------------------------------------------------------===//

// CHECK: pdl.pattern @TestCallWithArgsAndReturn
// CHECK: %[[ROOT:.*]] = operation
// CHECK: rewrite %[[ROOT]]
// CHECK: %[[REPL_OP:.*]] = operation "test.op"
// CHECK: %[[RESULTS:.*]] = results of %[[REPL_OP]]
// CHECK: replace %[[ROOT]] with(%[[RESULTS]] : !pdl.range<value>)
Rewrite TestRewrite(root: Op) -> ValueRange => root;
Pattern TestCallWithArgsAndReturn => replace root: Op with TestRewrite(op<test.op>);

// -----

// CHECK: pdl.pattern @TestExternalCall
// CHECK: %[[ROOT:.*]] = operation
// CHECK: rewrite %[[ROOT]]
// CHECK: %[[RESULTS:.*]] = apply_native_rewrite "TestRewrite"(%[[ROOT]] : !pdl.operation) : !pdl.range<value>
// CHECK: replace %[[ROOT]] with(%[[RESULTS]] : !pdl.range<value>)
Rewrite TestRewrite(op: Op) -> ValueRange;
Pattern TestExternalCall => replace root: Op with TestRewrite(root);

// -----

//===----------------------------------------------------------------------===//
// MemberAccessExpr
//===----------------------------------------------------------------------===//

// Handle implicit "all" operation results access.
// CHECK: pdl.pattern @OpAllResultMemberAccess
// CHECK: %[[OP0:.*]] = operation
// CHECK: %[[OP0_RES:.*]] = result 0 of %[[OP0]]
// CHECK: %[[OP1:.*]] = operation
// CHECK: %[[OP1_RES:.*]] = results of %[[OP1]]
// CHECK: operation(%[[OP0_RES]], %[[OP1_RES]] : !pdl.value, !pdl.range<value>)
Pattern OpAllResultMemberAccess {
  let singleVar: Value = op<>;
  let rangeVar: ValueRange = op<>;
  erase op<>(singleVar, rangeVar);
}

// -----

// Handle result indexing on unregistered op.
// CHECK: pdl.pattern @UnregisteredOpResultIndexing
// CHECK: %[[BAR_OP:.*]] = operation "my_dialect.unregistered_bar"
// CHECK: %[[BAR_RES:.*]] = result 0 of %[[BAR_OP]]
// CHECK: operation "my_dialect.unregistered_foo"(%[[BAR_RES]] : !pdl.value)
Pattern UnregisteredOpResultIndexing {
  let bar : Op<my_dialect.unregistered_bar>;
  let op = op<my_dialect.unregistered_foo>(bar.0);
  erase op;
}

// -----

// Handle implicit "named" operation results access.

#include "include/ops.td"

// CHECK: pdl.pattern @OpResultMemberAccess
// CHECK: %[[OP0:.*]] = operation
// CHECK: %[[RES:.*]] = results 0 of %[[OP0]] -> !pdl.value
// CHECK: %[[RES1:.*]] = results 0 of %[[OP0]] -> !pdl.value
// CHECK: %[[RES2:.*]] = results 1 of %[[OP0]] -> !pdl.range<value>
// CHECK: %[[RES3:.*]] = results 1 of %[[OP0]] -> !pdl.range<value>
// CHECK: operation(%[[RES]], %[[RES1]], %[[RES2]], %[[RES3]] : !pdl.value, !pdl.value, !pdl.range<value>, !pdl.range<value>)
Pattern OpResultMemberAccess {
  let op: Op<test.with_results>;
  erase op<>(op.0, op.result, op.1, op.var_result);
}

// -----

// CHECK: pdl.pattern @TupleMemberAccessNumber
// CHECK: %[[FIRST:.*]] = operation "test.first"
// CHECK: %[[SECOND:.*]] = operation "test.second"
// CHECK: rewrite %[[FIRST]] {
// CHECK:   replace %[[FIRST]] with %[[SECOND]]
Pattern TupleMemberAccessNumber {
  let firstOp = op<test.first>;
  let secondOp = op<test.second>(firstOp);
  let tuple = (firstOp, secondOp);
  replace tuple.0 with tuple.1;
}

// -----

// CHECK: pdl.pattern @TupleMemberAccessName
// CHECK: %[[FIRST:.*]] = operation "test.first"
// CHECK: %[[SECOND:.*]] = operation "test.second"
// CHECK: rewrite %[[FIRST]] {
// CHECK:   replace %[[FIRST]] with %[[SECOND]]
Pattern TupleMemberAccessName {
  let firstOp = op<test.first>;
  let secondOp = op<test.second>(firstOp);
  let tuple = (first = firstOp, second = secondOp);
  replace tuple.first with tuple.second;
}

// -----

//===----------------------------------------------------------------------===//
// RangeExpr
//===----------------------------------------------------------------------===//

// CHECK: pdl.pattern @RangeExpr
// CHECK: %[[ARG:.*]] = operand
// CHECK: %[[ARGS:.*]] = operands
// CHECK: %[[TYPE:.*]] = type
// CHECK: %[[TYPES:.*]] = types
// CHECK:   range : !pdl.range<value>
// CHECK:   range %[[ARG]], %[[ARGS]] : !pdl.value, !pdl.range<value>
// CHECK:   range : !pdl.range<type>
// CHECK:   range %[[TYPE]], %[[TYPES]] : !pdl.type, !pdl.range<type>
Pattern RangeExpr {
  replace op<>(arg: Value, args: ValueRange) -> (type: Type, types: TypeRange)
    with op<test.op>((), (arg, args)) -> ((), (type, types));
}

// -----

//===----------------------------------------------------------------------===//
// TypeExpr
//===----------------------------------------------------------------------===//

// CHECK: pdl.pattern @TypeExpr
// CHECK: %[[TYPE:.*]] = type : i32
// CHECK: operation({{.*}}) -> (%[[TYPE]] : !pdl.type)
Pattern TypeExpr => erase op<> -> (type<"i32">);
